﻿using System;

/*
 * 创建人：
 * 
 * 时间：
 * 
 * 说明：
 * 
 * 
 * 修改说明：
 * 
 * 
 */


namespace ConsoleTest.ChapterFour
{
    /// <summary>
    /// 应用程序域相关概念代码示例
    /// </summary>
    public class AppDomain
    {

        /// <summary>
        /// 该方法通过获取当前Appdomain的引用，列举当前应用程序域所加载的所有程序集
        /// </summary>
        public static void EnumerateAssembly()
        {
            //AppDomain 与线程的概念是正交的，
            //比如如果有两个AppDomain DA和DB，如果DA中的对象A的方法调用了DB中对象B的方法
            //那么主调方法和被调方法将在同一个线程中执行。
            //另外在一个AppDomain中可以启动多个线程。
            //AppDomain是一个应用程序执行的独立环境。
            System.AppDomain currentDomain = System.AppDomain.CurrentDomain;

            System.Console.WriteLine("CurrentDomain:"+currentDomain.FriendlyName);

            //枚举已经加载到应用程序域上下文中的程序集的名称
            foreach (System.Reflection.Assembly ass in currentDomain.GetAssemblies())
            {
                System.Console.WriteLine("Assembly:"+ass.FullName);
            }
        }

        /// <summary>
        /// 从AssForLoad 文件下加载另外一个可执行程序集
        /// </summary>
        public static void LoadAssembly()
        {
            //设置当前线程名称
            System.Threading.Thread.CurrentThread.Name = "Loader";
            //表示可以添加到应用程序域中的程序集的相关信息
            System.AppDomainSetup info = new AppDomainSetup();
            //设置需要加载程序集的目录
            info.ApplicationBase = "file:///" + @"D:\Project\NET2.0实战笔记\CSharp_NET2_Practical\ConsoleTest\4-CLR\AssForLoad";

            //从外部加载程序集时需要设置对改程序能够进行访问的权限
            string strFullPath = info.ApplicationBase +"\\AssToLoad.exe";
            System.Security.PermissionSet ps=new System.Security.PermissionSet(System.Security.Permissions.PermissionState.None);
            ps.AddPermission(new System.Security.Permissions.FileIOPermission(System.Security.Permissions.FileIOPermissionAccess.AllAccess
                , strFullPath ));



            //根据设置的程序集的信息创建新的应用程序域
            System.AppDomain NewDomain = System.AppDomain.CreateDomain("NewDomain", null, info,ps);

            System.Console.WriteLine("Thread ID:{0} Name:{1} Calling ExecuteAssebmly method form appdomain{2}"
                ,System.Threading.Thread.CurrentThread.ManagedThreadId
                ,System.Threading.Thread.CurrentThread.Name
                ,System.AppDomain.CurrentDomain.FriendlyName);

            //在新创建的应用程序内部执行程序集
            /*
             * 虽然已经添加访问权限但是仍然有以下错误：
             * 
             * 请求“System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”类型的权限已失败
             */
            NewDomain.ExecuteAssembly("AssToLoad.exe");
            //程序集加载到应用程序域后就不能卸载了，不过可以将整个应用程序卸载
            //不推荐这样做，因为卸载程序域将会使得所有的托管对象被垃圾回收器强制回收
            //如果存在非托管代码可能会有其他问题。
            System.AppDomain.Unload(NewDomain);


        }

        /// <summary>
        /// 在其他AppDomain的上下文中运行代码
        /// </summary>
        public static void RunInOtherAppDomian()
        {
            System.Threading.Thread.CurrentThread.Name = "MyThread";
            System.AppDomain newDomain = System.AppDomain.CreateDomain("newDomain");

            //由DoCallBack方法使用
            //Used by DoCallBack for cross-application domain calls.
            System.CrossAppDomainDelegate deleg = new CrossAppDomainDelegate(RunCode);

            newDomain.DoCallBack(deleg);
            System.AppDomain.Unload(newDomain);
        }

        /// <summary>
        /// 要在其他Appdomain中运行的代码
        /// </summary>
        public static void RunCode()
        {
            System.Console.WriteLine("Thread : {0} execute RunCode() inside the appdomain{1} :"
                ,System.Threading.Thread.CurrentThread.Name
                ,System.AppDomain.CurrentDomain.FriendlyName);
        }

        /// <summary>
        /// 在同一个进程的应用程序域之间共享信息
        /// </summary>
        public static void DataAccessCrossDomain()
        {
            /*
             * 该方法没有体现两个程序域之间的交互
             * 
             * .NET Remoting技术用于在程序域之间共享数据
             */
            System.AppDomain newAppDomain = System.AppDomain.CreateDomain("newAppDomain");

            System.CrossAppDomainDelegate deleg = new CrossAppDomainDelegate(SetData);
            newAppDomain.DoCallBack(deleg);

            int AnInteger=(int)newAppDomain.GetData("AnInteger");
            System.Console.WriteLine("GetData: {0} in Appdomain:{1}"
                                                    , AnInteger
                                                    , System.AppDomain.CurrentDomain.FriendlyName);
            System.AppDomain.Unload(newAppDomain);
        }

        /// <summary>
        /// 在应用程序域中保存数据
        /// </summary>
        public static void SetData()
        {
            //该方法运行在newAppdomain程序域中，并设置数据
            System.Console.WriteLine("SetData: {0} in Appdomain:{1}"
                                                    ,111
                                                    ,System.AppDomain.CurrentDomain.FriendlyName);
            System.AppDomain.CurrentDomain.SetData("AnInteger", 111);
        }
    }
 
}